import struct

############################################################
#
# socket read functions
#
############################################################

def read_n_bytes( sock, n ):
    output = ''
    while len(output) < n:
        chunk = sock.recv(n - len(output))
        if not chunk:
            raise RuntimeError("socket connection broken")
        output = output + chunk
    return output


def read_integer( sock ):
    return struct.unpack( '>i',
                          read_n_bytes( sock, 4 ) )[0]

def read_string( sock ):
    size = read_integer( sock )
    return struct.unpack( '>%ds' % (size,),
                          read_n_bytes( sock, size ) )[0]

def read_boolean( sock ):
    return struct.unpack( '>?',
                          read_n_bytes( sock, 1 ) )[0]

def read_long( sock ):
    return struct.unpack( '>l',
                          read_n_bytes( sock, 4 ) )[0]

def read_float( sock ):
    return struct.unpack( '>f',
                          read_n_bytes( sock, 4 ) )[0]

def read_double( sock ):
    return struct.unpack( '>d',
                          read_n_bytes( sock, 8 ) )[0]


############################################################
#
# socket write functions
#
############################################################

def write_to_socket( sock, input ):
    msglen = len( input )
    totalsent = 0
    while totalsent < msglen:
        sent = sock.send(input[totalsent:])
        if not sent:
            raise RuntimeError("socket connection broken")
        totalsent = totalsent + sent


def write_packed_data( sock, input, fmt ):
    write_to_socket( sock, struct.pack( fmt, input ) )

def write_integer( sock, input ):
    write_packed_data( sock, input, '>i' )

def write_string( sock, input ):
    # input has to be isinstance(str)
    l = len(input)
    write_integer( sock, l )
    fmt = '>%ds' % ( l, )
    write_packed_data( sock, input, fmt )

def write_boolean( sock, input ):
    write_packed_data( sock, input, '>?' )

def write_long( sock, input ):
    write_packed_data( sock, input, '>l' )

def write_float( sock, input ):
    write_packed_data( sock, input, '>f' )

def write_double( sock, input ):
    write_packed_data( sock, input, '>d' )

